package com.heiTie.heiTie.common;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import org.springframework.lang.Nullable;

import java.util.List;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BaseResponse<T> {

    public static final Integer SUCCESS = 200;

    private Integer code;

    private String msg;

    private T data;

    private List<TraceProcess> processes;

    public BaseResponse() {
    }

    public BaseResponse(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public BaseResponse(Integer code, String msg, @Nullable T data) {
        this(code, msg);
        this.data = data;
    }

    public BaseResponse(Integer code, String msg, List<TraceProcess> processes, @Nullable T data) {
        this(code, msg);
        this.data = data;
        this.processes = processes;
    }

    public BaseResponse(Integer code, List<TraceProcess> processes, @Nullable T data) {
        this(code, "");
        this.data = data;
        this.processes = processes;
    }

    public static <T> BaseResponse<T> ok(T info) {
        return new DefaultBuilder().info(info);
    }

    public static <T> BaseResponse<T> ok(T info, String msg) {
        return new DefaultBuilder().withMsg(msg).info(info);
    }

    public static <T> BaseResponse<T> ok(T info, List<TraceProcess> processes) {
        return new DefaultBuilder().withProcesses(processes).info(info);
    }

    public static <T> BaseResponse<T> ok(Integer code, String msg) {
        return new DefaultBuilder().code(code).msg(msg);
    }

    public static <T> BaseResponse<T> error(Integer code, String msg) {
        return new DefaultBuilder().code(code).msg(msg);
    }

    public static <T> BaseResponse<T> error(DefaultCodeEnum codeEnum) {
        return new DefaultBuilder().code(codeEnum.getCode()).msg(codeEnum.getMessage());
    }

    public interface BodyBuilder {

        BodyBuilder code(Integer code);

        BodyBuilder withProcesses(List<TraceProcess> processes);

        BodyBuilder withMsg(String msg);

        <T> BaseResponse<T> info(@Nullable T info);

        <T> BaseResponse<T> msg(@Nullable String msg);

        <T> BaseResponse<T> build();
    }

    private static class DefaultBuilder implements BodyBuilder {

        private Integer code = SUCCESS;

        private List<TraceProcess> processes;

        private String msg;

        @Override
        public BodyBuilder code(Integer code) {
            this.code = code;
            return this;
        }

        @Override
        public BodyBuilder withProcesses(List<TraceProcess> processes) {
            this.processes = processes;
            return this;
        }

        @Override
        public BodyBuilder withMsg(String msg) {
            this.msg = msg;
            return this;
        }

        @Override
        public <T> BaseResponse<T> info(T info) {
            return new BaseResponse<>(code, msg, processes, info);
        }

        @Override
        public <T> BaseResponse<T> msg(String msg) {
            return new BaseResponse<>(code, msg);
        }

        @Override
        public <T> BaseResponse<T> build() {
            return info(null);
        }
    }

    @Data
    public static class TraceProcess {
        String desc;

        Object result;
    }
}
